package com.zzjr.tools.java.ssm.core;

import com.zzjr.tools.java.ssm.constants.AutoCodeConstants;
import com.zzjr.tools.java.ssm.factory.*;
import com.zzjr.tools.java.ssm.table.CWCheckBoxRenderer;
import com.zzjr.tools.java.ssm.table.CheckBoxCellEditor;
import com.zzjr.tools.java.ssm.utils.DBUtils;
import com.zzjr.tools.java.ssm.utils.IOUtils;

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * Description:Spring + SpringMVC + Mybatis自动代码生成器
 *
 * @author <a href="mailto:liupengyao@zuozh.com">Aromarich</a>
 * @Date Create on 2015年10月12日
 * @since version1.0 Copyright 2015 ZZJR All Rights Reserved.
 */
public class GenerateSsmCodeWindow {

    /**************************** 数据库相关连接 **********************************/

    // 默认数据库连接
    private static final String DEFAULT_DB_URL = "jdbc:mysql://localhost:3306";

    // 默认数据库用户名
    private static final String DEFAULT_DB_USERNAME = "root";

    // 默认数据库密码
    private static final String DEFAULT_DB_PASSWORD = "123456";

    // 数据库连接
    private Connection dbConn;

    /**************************** 公用变量 **********************************/
    // 数据库名称列表
    List<String> dbNameList = new ArrayList<String>();

    // 表名列表
    List<String> tableNameList = new ArrayList<String>();

    // 选中的数据库名称
    private static String selectedDbName = "zzjr_server";

    /**************************** 页面组件 **********************************/

    // 数据库连接Frame
    private JFrame frmConnDB;

    // 数据库连接URL标签
    private JLabel urlLabel;

    // 数据库连接URL文本输入框
    private JTextField urlTextField;

    // 数据库用户名标签
    private JLabel userNameLabel;

    // 用户名文本输入框
    private JTextField userNameTextField;

    // 数据库密码标签
    private JLabel pwdLabel;

    // 数据库密码文本输入框
    private JTextField pwdTextField;

    // 链接数据库的Button
    private JButton connectButton;

    // 显示数据库列表的下拉列表框
    @SuppressWarnings("rawtypes")
    private JComboBox dbNameListComboBox;

    // 数据库连接面板
    private JPanel dbConnPanel;

    // 数据库表格显示面板
    private JPanel tableListPanel;

    // 选择数据库标签
    private JLabel chooseDbLabel;

    // 显示数据库表名的表格组件
    private JTable tableNameJTable;

    // 显示选择表格的标签
    private JLabel chooseTableLabel;

    // 包名的标签
    private JLabel packageNameLabel;

    // 包名文本输入框
    private JTextField packageNameTextField;

    // Dao后缀文本编辑框
    private JTextField daoTextField;

    // 业务类标签
    private JLabel serviceLabel;

    // 业务类后缀文本输入框
    private JTextField serviceTextField;

    // 自动生成代码Code
    private JButton autoGeneCodeBtn;

    // 显示表格的按钮
    private JButton showTableBtn;

    // 文件选择器
    private JFileChooser fileChooser;

    private JTextField codeSaveDirTextField;

    private JLabel authorLabel;

    private JTextField authorTextField;

    private JScrollPane scrollPane; //定义带有滚动条的面板

    /**
     * 启动应用
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                try {
                    GenerateSsmCodeWindow window = new GenerateSsmCodeWindow();
                    window.frmConnDB.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 创建应用
     */
    public GenerateSsmCodeWindow() {
        initialize();
    }

    /**
     * 初始化面板内容
     */
    private void initialize() {
        // 构建Frame框
        constructFrame();

        // 构建面板
        JPanel panel = contructPanel();

        // 构建标签和文本框
        constructLabelAndTextField(panel);

        codeSaveDirTextField = new JTextField();
        codeSaveDirTextField.setText("C:\\Users\\Administrator\\Desktop");
        codeSaveDirTextField.setBounds(14, 390, 401, 24);
        dbConnPanel.add(codeSaveDirTextField);
        codeSaveDirTextField.setColumns(10);

        JButton chooseCodeDirButton = new JButton("代码存放目录");
        chooseCodeDirButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {
                // 单击创建JFileChooser
                fileChooser = new JFileChooser();
                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                fileChooser.setBounds(14, 393, 523, 82);
                dbConnPanel.add(fileChooser);

                int state = fileChooser.showOpenDialog(null);// 此句是打开文件选择器界面的触发语句
                if (state == 1) {
                    return;
                } else {
                    File f = fileChooser.getSelectedFile();// f为选择到的目录
                    codeSaveDirTextField.setText(f.getAbsolutePath());
                }
            }
        });
        chooseCodeDirButton.setBounds(296, 434, 123, 27);
        dbConnPanel.add(chooseCodeDirButton);

        authorLabel = new JLabel("作者:");
        authorLabel.setBounds(62, 436, 38, 23);
        dbConnPanel.add(authorLabel);

        authorTextField = new JTextField();
        authorTextField.setText("Aromarich");
        authorTextField.setBounds(104, 435, 120, 24);
        dbConnPanel.add(authorTextField);
        authorTextField.setColumns(10);

    }

    /**
     * 构建Frame框
     */
    private void constructFrame() {
        frmConnDB = new JFrame();
        frmConnDB.setTitle("Java代码生成器");
        frmConnDB.setBounds(100, 100, 1500, 920);
        frmConnDB.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    /**
     * 构建Panel面板
     *
     * @return
     */
    private JPanel contructPanel() {
        dbConnPanel = new JPanel();
        dbConnPanel.setBorder(new LineBorder(new Color(255, 0, 0), 3));
        dbConnPanel.setBounds(0, 0, 500, 833);
        frmConnDB.getContentPane().setLayout(new BorderLayout());
        frmConnDB.getContentPane().add(dbConnPanel, BorderLayout.CENTER);
        tableListPanel = new JPanel();
        tableListPanel.setBorder(new LineBorder(new Color(0, 0, 0), 3));
        frmConnDB.getContentPane().add(tableListPanel, BorderLayout.EAST);
        tableListPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));

        chooseTableLabel = new JLabel("请选择所有需要自动生成代码的表格");
        tableListPanel.add(chooseTableLabel);

        tableNameJTable = new JTable();
        scrollPane = new JScrollPane();
        scrollPane.setPreferredSize(new Dimension(500, 800));
        scrollPane.getViewport().setView(tableNameJTable); //把二维数据表格放到滚动面板中
        tableListPanel.add(scrollPane);

        autoGeneCodeBtn = new JButton("自动生成代码");
        autoGeneCodeBtn.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {
                // 设置全局属性，eg 包名，dao后缀名，service后缀名
                setGlobalProperties();

                try {
                    // 生成包所对应的目录
                    String packageFullPath = IOUtils.createPackageDirPath();
                    AutoCodeConstants.PACKAGE_FULL_PATH = packageFullPath;

                    // 遍历选中的表格，自动生成对应的代码
                    autoGenerateCode();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        tableListPanel.add(autoGeneCodeBtn);

        return dbConnPanel;
    }

    /**
     * 设置全局属性，eg 包名，dao后缀名，service后缀名
     */
    protected void setGlobalProperties() {
        // 设置包名
        AutoCodeConstants.PACKAGE_NAME = packageNameTextField.getText().trim();

        // 设置DAO后缀
        AutoCodeConstants.DAO_SUFFIX = daoTextField.getText().trim();

        // 设置Manager后缀
        AutoCodeConstants.SERVICE_SUFFIX = serviceTextField.getText().trim();

        // 设置代码存放目录：
        AutoCodeConstants.CODE_GENERATE_DIR = codeSaveDirTextField.getText().trim();

        // 设置作者：
        AutoCodeConstants.AUTHOR_NAME = authorTextField.getText().trim();
    }

    /**
     * 遍历选中的表格，自动生成对应的代码
     *
     * @throws IOException
     */
    protected void autoGenerateCode() throws IOException {
        // 1.获取表格中所有选中的表的表名。
        int dataLength = tableNameList.size();
        for (int index = 0; index < dataLength; index++) {

            // 判断是否选中
            boolean isCheck = (Boolean) tableNameJTable.getValueAt(index, 0);
            if (isCheck) {// 选中的话则进行相关操作
                // 1.1获取表名
                String tableName = (String) tableNameJTable.getValueAt(index, 2);
                System.out.println("*****************选择的表名是:" + tableName + "*******************");

                // 1.2生成对应的Model对象，DO
                ModelFactory.generateModel(tableName);

                // 1.3生成对应的Mapper配置文件
                MapperFactory.generateMapperXml(tableName);

                // 1.4生成对应的Dao文件
                DaoFactory.generateDao(tableName);

                // 1.5生成对应的Dao实现类文件
                DaoImplFactory.generateDaoImpl(tableName);

                // 1.6生成对应的Service文件
                ServiceFactory.generateService(tableName);

                // 1.7生成对应的Service实现类文件
                ServiceImplFactory.generateServiceImpl(tableName);
            }
        }
    }

    /**
     * 构建标签和文本框
     *
     * @param panel
     */
    @SuppressWarnings("rawtypes")
    private void constructLabelAndTextField(JPanel panel) {
        dbConnPanel.setLayout(null);
        JLabel dbUrlLabel = new JLabel("数据库连接URL:");
        dbUrlLabel.setBounds(28, 13, 77, 18);
        dbUrlLabel.setVerticalAlignment(SwingConstants.TOP);
        panel.add(dbUrlLabel);

        urlTextField = new JTextField();
        urlTextField.setBounds(140, 10, 243, 24);
        panel.add(urlTextField);
        urlTextField.setColumns(25);
        urlTextField.setText(DEFAULT_DB_URL);

        userNameLabel = new JLabel("用户名:");
        userNameLabel.setBounds(82, 44, 53, 18);
        userNameLabel.setHorizontalAlignment(SwingConstants.LEFT);
        userNameLabel.setVerticalAlignment(SwingConstants.TOP);
        panel.add(userNameLabel);

        userNameTextField = new JTextField();
        userNameTextField.setBounds(140, 41, 243, 24);
        panel.add(userNameTextField);
        userNameTextField.setColumns(32);
        userNameTextField.setText(DEFAULT_DB_USERNAME);

        pwdLabel = new JLabel("密码:");
        pwdLabel.setBounds(97, 75, 38, 18);
        panel.add(pwdLabel);

        pwdTextField = new JTextField();
        pwdTextField.setBounds(140, 72, 243, 24);
        panel.add(pwdTextField);
        pwdTextField.setColumns(32);
        pwdTextField.setText(DEFAULT_DB_PASSWORD);

        connectButton = new JButton("连接数据库");
        connectButton.setBounds(82, 161, 107, 27);
        connectButton.addActionListener(new ActionListener() {

            @SuppressWarnings("unchecked")
            public void actionPerformed(ActionEvent event) {

                String url = urlTextField.getText();
                String username = userNameTextField.getText();
                String pwd = pwdTextField.getText();

                dbConn = DBUtils.getDBConnection(url, username, pwd);
                if (null != dbConn) {
                    AutoCodeConstants.DB_CONN = dbConn;
                    System.out.println("获取数据库连接成功！dbConn=" + dbConn);

                    // dbNameList 用于获取数据库表名
                    dbNameList = DBUtils.getDbList(dbConn);
                    dbNameListComboBox.setVisible(true);
                    for (String dbName : dbNameList) {
                        dbNameListComboBox.addItem(dbName);
                    }
                }
            }
        });
        panel.add(connectButton);

        chooseDbLabel = new JLabel("请选择数据库");
        chooseDbLabel.setBounds(92, 198, 90, 18);
        dbConnPanel.add(chooseDbLabel);

        dbNameListComboBox = new JComboBox();
        dbNameListComboBox.setBounds(210, 195, 173, 24);
        dbConnPanel.add(dbNameListComboBox);
        dbNameListComboBox.setVisible(false);

        urlLabel = new JLabel("");
        urlLabel.setBounds(255, 174, 0, 0);
        panel.add(urlLabel);

        showTableBtn = new JButton("查看该数据库下的所有表");
        // 查询数据库表按钮触发事件
        showTableBtn.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {

                selectedDbName = (String) dbNameListComboBox.getSelectedItem();
                AutoCodeConstants.DB_NAME = selectedDbName;

                // 根据选择的数据库表名获取该数据库下所有的表
                tableNameList = DBUtils.getTableNameList(dbConn, selectedDbName);

                DefaultTableModel tableModel = (DefaultTableModel) tableNameJTable.getModel();
                String[] headers = {"", "序号", "列名"};
                Object[][] data = new Object[tableNameList.size()][3];
                int index = 0;
                for (String tableName : tableNameList) {
                    index++;
                    data[index - 1][0] = new Boolean(false);
                    data[index - 1][1] = index;
                    data[index - 1][2] = tableName;
                }
                tableModel.setDataVector(data, headers);
                tableNameJTable.getColumnModel().getColumn(0).setCellEditor(new CheckBoxCellEditor());
                tableNameJTable.getColumnModel().getColumn(0).setCellRenderer(new CWCheckBoxRenderer());
                tableNameJTable.setPreferredScrollableViewportSize(new Dimension(600, 100));
                tableNameJTable.setSelectionBackground(Color.white);// 设置所选择行的背景色
                tableNameJTable.setSelectionForeground(Color.red);// 设置所选择行的前景色
                FitTableColumns(tableNameJTable);
                frmConnDB.repaint();
                frmConnDB.revalidate();
            }
        });
        showTableBtn.setBounds(82, 229, 301, 27);
        dbConnPanel.add(showTableBtn);

        packageNameLabel = new JLabel("请输入包名:");
        packageNameLabel.setBounds(99, 297, 100, 18);
        dbConnPanel.add(packageNameLabel);

        packageNameTextField = new JTextField();
        packageNameTextField.setText("com.beihui");
        packageNameTextField.setBounds(197, 294, 218, 24);
        dbConnPanel.add(packageNameTextField);
        packageNameTextField.setColumns(10);

        JLabel daoLabel = new JLabel("请输入DAO后缀名：");
        daoLabel.setBounds(64, 328, 140, 18);
        dbConnPanel.add(daoLabel);

        daoTextField = new JTextField();
        daoTextField.setText("Dao");
        daoTextField.setBounds(197, 325, 218, 24);
        dbConnPanel.add(daoTextField);
        daoTextField.setColumns(10);

        serviceLabel = new JLabel("请输入单表Service后缀：");
        serviceLabel.setBounds(14, 359, 185, 18);
        dbConnPanel.add(serviceLabel);

        serviceTextField = new JTextField();
        serviceTextField.setText("Manager");
        serviceTextField.setBounds(197, 356, 218, 24);
        dbConnPanel.add(serviceTextField);
        serviceTextField.setColumns(10);

    }

    /**
     * 表格的列自适应宽度
     *
     * @param myTable
     */
    @SuppressWarnings("rawtypes")
    public void FitTableColumns(JTable myTable) {
        JTableHeader header = myTable.getTableHeader();
        int rowCount = myTable.getRowCount();

        Enumeration columns = myTable.getColumnModel().getColumns();
        while (columns.hasMoreElements()) {
            TableColumn column = (TableColumn) columns.nextElement();
            int col = header.getColumnModel().getColumnIndex(column.getIdentifier());
            int width = (int) myTable.getTableHeader().getDefaultRenderer()
                    .getTableCellRendererComponent(myTable, column.getIdentifier(), false, false, -1, col)
                    .getPreferredSize().getWidth();
            for (int row = 0; row < rowCount; row++) {
                int preferedWidth = (int) myTable.getCellRenderer(row, col)
                        .getTableCellRendererComponent(myTable, myTable.getValueAt(row, col), false, false, row, col)
                        .getPreferredSize().getWidth();
                width = Math.max(width, preferedWidth);
            }
            header.setResizingColumn(column); // 此行很重要
            column.setWidth(width + myTable.getIntercellSpacing().width);
        }
    }

}
